Skip to main content

EVENT BUBBLING

Lesson Objectives#

  1. Describe event bubbling
  2. Prove that event bubbling occurs
  3. Access the event parameter
  4. Differentiate between an event's target and currentTarget
  5. Stop event propagation
  6. Have an event handler return false

Describe event bubbling#

When elements are nested within the DOM, the DOM needs a way to decide which elements ought to trigger an event.

If a click event listener is set on the outer element, the green box, will a click on the inner element, the pink box, also trigger the event?

Does the pink box somehow 'block' the event? Does the "click me" text block it?

What belongs to the green box?

  $('.outside').on('click', () => {    console.log('OUTSIDE is clicked');  });

Nothing within the green box blocks the event. Everything belongs to the green box. No matter where inside the green box you click, you'll get the console log.

Bubbles#

When you click on the pink box, this is the lowest level of your mouse location, the target of the event. JS checks to see if there is an event listener on this element.

Then, the event bubbles up to the parent, the green box, and checks to see if there is a listener there.

But, it doesn't stop there!

The event bubbles up through all parents to the body, and checks that too!

The event finally stops bubbling at the document.

Prove that event bubbling occurs#

So, if we set a listener on the pink element, the question is, will that also trigger the listener on the green one? Will it "bubble" up?

  $('.outside').on('click', () => {    console.log('OUTSIDE is clicked');  });
  $('.inside').on('click', () => {    console.log('INSIDE is clicked');  });

Clicking on the innermost element:

Test bubbling: Set listener on body#

  $('.outside').on('click', () => {    console.log('OUTSIDE is clicked');  });
  $('.inside').on('click', () => {    console.log('INSIDE is clicked');  });
  $('body').on('click', () => {    console.log('BODY is clicked');  });

Clicking on the innermost element:

Access the event parameter#

  $('.inside').on('click', (event) => {    console.log('INSIDE is clicked');  });

When the .on method (or any JS event listener method) runs the callback function, it supplies the callback with an argument: an object that represents the event.

We can use this param in our callback. Call it what you like: you will see e, ev, event, etc.

Differentiate between an event's target and currentTarget#

On the event object, you can see the innermost thing that was clicked with event.target, and the thing that has the event listener with event.currentTarget.

Comment out the inside and body event listeners

On the outside event listener:

  $('.outside').on('click', (event) => {    console.log('OUTSIDE target is: ', event.target);    console.log('OUTSIDE currentTarget is: ', event.currentTarget);  });

If you click the green box (the outside element):

target and currentTarget are the same.

If you click the pink element (the inner element), we expect the event to bubble to the outside and trigger the event listener:

target is the innermost element that was clicked: the inside pink one.

currentTarget is the element on which the event listener is set: the outside green one.

Consider this#

  $('.outside').on('click', (event) => {    console.log('OUTSIDE target is: ', event.target);    console.log('OUTSIDE currentTarget is: ', event.currentTarget);  });
  $('.inside').on('click', (event) => {    console.log('INSIDE target is: ', event.target);    console.log('INSIDE currentTarget is: ', event.currentTarget);  });
  $('body').on('click', (event) => {    console.log('BODY target is: ', event.target);    console.log('Body currentTarget is: ', event.currentTarget);  });

If you click on the body, which listeners will be triggered? what will be the value of target for each listener? and what will be the value of currentTarget for each listener?

If you click on the outside box, which listeners will be triggered, what will be the value of target for each listener? and what will be the value of currentTarget for each listener?

If you click on the inner box, which listeners will be triggered? what will be the value of target for each listener? and what will be the value of currentTarget for each listener?

Element targeting with jQuery#

Let's say I make a few copies of the squares:

    <div class="outside">      <p>Click me ... ?</p>        <div class="inside"></div>    </div>
    <div class="outside">      <p>Click me ... ?</p>        <div class="inside"></div>    </div>
    <div class="outside">      <p>Click me ... ?</p>        <div class="inside"></div>    </div>

By wrapping event.currentTarget in jQuery I can use jQuery methods on the target, and only affect the elements I clicked (not the others)

$(event.currentTarget).css('background-color', 'black');
  $('.outside').on('click', (event) => {    $(event.currentTarget).css('background-color', 'black');  });

Stop event propagation#

If you want to isolate an element and prevent bubbling, use

  • event.stopPropagation()
  $('.inside').on('click', (event) => {    console.log('INSIDE target is: ', event.target);    console.log('INSIDE currentTarget is: ', event.currentTarget);    event.stopPropagation();  });

Clicking on the inside element no longer triggers the outer event listeners:

Clicking on the outer event listener still triggers bubbling as expected:

Have an event handler return false#

When using jQuery, you can use return false within your event handlers to stop all of the default behavior associated with events, such as bubbling.

  • event.stopPropagation() to stop bubbling
  • event.preventDefault() to stop forms from refreshing the page
  $('.outside').on('click', (event) => {    console.log('OUTSIDE target is: ', event.target);    console.log('OUTSIDE currentTarget is: ', event.currentTarget);    return false;  });
  $('.inside').on('click', (event) => {    console.log('INSIDE target is: ', event.target);    console.log('INSIDE currentTarget is: ', event.currentTarget);    return false;  });
  $('body').on('click', (event) => {    console.log('BODY target is: ', event.target);    console.log('Body currentTarget is: ', event.currentTarget);    return false;  });